/*
 * Wednesday, 2nd September 2020
 * (c) Victor
 * @Description `measure`
 * @Usage `ins = new Distance(map), ins.init(), ins.destroy()`
 */

import D2c from 'd2c'
export class Distance {
  map
  measures = []
  currentMeasure = null
  isActive = false
  constructor(map) {
    this.map = map
  }
  init = () => {
    this.disableDblclick()
    this.updateMeasure()
    this.bindEvent()
    this.isActive = true
  }
  bindEvent = () => {
    this.map.on('click', this.handleClick)
    this.map.on('dblclick', this.updateMeasure)
  }
  offEvent = () => {
    this.map.off('click', this.handleClick)
    this.map.off('dblclick', this.updateMeasure)
  }
  handleClick = (e) => {
    this.currentMeasure.addLine(e)
  }
  updateMeasure = () => {
    const count = this.measures.length
    this.currentMeasure = this.measures[count] = new D2c.distanceLayer(this.map)
  }
  disableDblclick = () => {
    this.map.doubleClickZoom.disable()
  }
  enableDblclick = () => {
    this.map.doubleClickZoom.enable()
  }
  destroy = () => {
    this.measures.map((measure) => {
      measure.remove()
      measure.removeMarker()
    })
    this.measures = []
    this.offEvent()
    this.isActive = false
  }
}

export class Area {
  map
  measures = []
  currentMeasure = null
  isActive = false
  constructor(map) {
    this.map = map
  }
  init = () => {
    this.disableDblclick()
    this.updateMeasure()
    this.bindEvent()
    this.isActive = true
  }
  bindEvent = () => {
    this.map.on('click', this.handleClick)
    this.map.on('dblclick', this.updateMeasure)
  }
  offEvent = () => {
    this.map.off('click', this.handleClick)
    this.map.off('dblclick', this.updateMeasure)
  }
  handleClick = (e) => {
    this.currentMeasure.addPolygon(e)
  }
  updateMeasure = () => {
    const count = this.measures.length
    this.currentMeasure = this.measures[count] = new D2c.areaLayer(this.map)
  }
  disableDblclick = () => {
    this.map.doubleClickZoom.disable()
  }
  enableDblclick = () => {
    this.map.doubleClickZoom.enable()
  }
  destroy = () => {
    this.measures.map((measure) => {
      measure.remove()
      measure.removeMarker()
    })
    this.measures = []
    this.offEvent()
    this.isActive = false
  }
}

// 点击查询
export class ClickSearch {
  map = null
  isDom = true
  popup = null
  layers = []
  light = null
  constructor(map, layers, light = false) {
    this.map = map
    this.layers.push(...layers)
    this.light = light
  }
  init = () => {
    this.bindEvent()
  }
  bindEvent = () => {
    this.map.on('click', this.handleClick)
  }
  offEvent = () => {
    this.map.off('click', this.handleClick)
  }
  handleClick = (e) => {
    this.popup = new D2c.Popup({
      closeButton: true,
    })
    // console.log(this.map, this.popup)
    // 获取所点击的要素
    let result
    if (this.layers.length) {
      const layers = [...this.layers]
      if (this.map.getLayer('light-area-layer')) {
        layers.push({
          id: 'light-area-layer',
        })
      }
      result = this.map.queryRenderedFeatures(e.point, {
        layers: layers.map((layer) => layer.id),
      })
    } else {
      result = this.map.queryRenderedFeatures(e.point)
    }
    if (result.length) {
      if (!this.isDom) {
        let dom = this.createPopupDom(result.slice(0, 1))
        dom.style.display = 'block'
        this.popup.setDOMContent(dom)
      } else {
        let html = this.createPopupHtml(result.slice(0, 1))
        this.popup.setHTML(html)
        // this.popup.setDOMContent(result.slice(0, 1))
      }
      this.popup.setLngLat(e.lngLat).addTo(this.map)
      if (this.light) {
        this.lightLayer(result[0])
      }
    }
  }

  lightLayer = (feature) => {
    this.clearLightLayer()
    let { minzoom, source, paint, type } = feature.layer
    let layer = {
      filter: ['==', 'ID_1', feature.properties.ID_1],
      id: 'light-layer',
      minzoom,
      source,
      paint,
      'source-layer': feature.layer['source-layer'],
      type,
    }
    layer.paint['fill-extrusion-color'] = 'red'
    this.map.addLayer(layer)
  }
  clearLightLayer = () => {
    if (this.map.getLayer('light-layer')) {
      this.map.removeLayer('light-layer')
    }
  }
  // 创建popup的显示html
  createPopupHtml = (features) => {
    this.isDom = true
    const renderArr = (arr) => arr.toString().replaceAll(',', '')
    const renderProperty = ({ key, value }) => `
      <div class="property">
        <span class="property_key"><b>${key}：</b></span>
        <span class="property_value">${value}</span>
      </div>`
    const renderFeature = (feature) =>
      `<div class="popup_feature">
        <div class="title">属性信息</div>
        <div class="content">
        ${renderArr(
          Object.keys(feature.properties)
            .filter((i) => !window.clickSearchObjectFilter.includes(i))
            .map((key) =>
              renderProperty({ key, value: feature.properties[key] })
            )
        )}
        </div>
      </div>`
    return `<div class="popup_features">
          ${renderArr(features.map(renderFeature))}
        </div>`
  }
  createPopupDom = (dom) => {
    this.isDom = false
    // 默认dom
    let div = document.createElement('div')
    div.innerHTML = JSON.stringify(dom)
    return div
  }

  // 销毁
  destroy = () => {
    this.popup.remove()
    this.clearLightLayer()
    this.offEvent()
  }
}

export class spaceSearch {
  map = null
  dom = null
  layers = []
  sourceId = 'space-search-polygon'
  geojson = {
    type: 'geojson',
    data: {
      type: 'Feature',
      geometry: {
        type: 'Polygon',
        coordinates: [[]],
      },
    },
  }
  layer = {
    id: 'search-polygon-layer',
    source: 'space-search-polygon',
    type: 'fill',
    paint: {
      'fill-color': 'red',
      'fill-opacity': 0.2,
    },
  }
  startPoint = null
  endPoint = null
  startLng = { lng: 0, lat: 0 }
  endLng = { lng: 0, lat: 0 }
  constructor(map, dom, layers) {
    this.map = map
    this.dom = dom
    this.layers = layers
  }
  init = () => {
    this.map.dragPan.disable()

    this.addSources()
    this.bindEvent()
  }
  addSources = () => {
    if (!this.map.getSource(this.sourceId)) {
      this.map.addSource(this.sourceId, this.geojson)
    }
    if (!this.map.getLayer(this.layer.id)) {
      this.map.addLayer(this.layer)
    }
    this.startLng = { lng: 0, lat: 0 }
    this.endLng = this.startLng
    this.setLatlng()
  }
  removeSource = () => {
    if (this.map.getSource('space-search-polygon')) {
      this.map.removeSource('space-search-polygon', this.geojson)
    }
    if (this.map.getLayer(this.layer.id)) {
      this.map.removeLayer(this.layer.id)
    }
  }
  setLatlng = () => {
    this.geojson.data.geometry.coordinates = [
      [
        [this.startLng.lng, this.startLng.lat],
        [this.endLng.lng, this.startLng.lat],
        [this.endLng.lng, this.endLng.lat],
        [this.startLng.lng, this.endLng.lat],
        [this.startLng.lng, this.startLng.lat],
      ],
    ]
    this.map.getSource('space-search-polygon').setData(this.geojson.data)
  }
  onMouseDown = (e) => {
    const { lngLat, point } = e
    this.startPoint = point
    this.startLng = lngLat
    this.endLng = lngLat
    this.setLatlng()
    this.map.on('mousemove', this.onMouseMove)
  }
  onMouseMove = (e) => {
    const { lngLat, point } = e
    this.endLng = lngLat
    this.endPoint = point
    this.setLatlng()
  }
  onMouseUp = () => {
    this.queryFeatures()
    this.startLng = { lng: 0, lat: 0 }
    this.endLng = this.startLng
    // this.setLatlng();
    this.map.off('mousemove', this.onMouseMove)
  }
  queryFeatures = () => {
    this.dom.style.display = 'block'
    const ids = this.layers.map((layer) => layer.id)
    let statistics = {}
    this.layers.forEach(
      (i) =>
        (statistics[i.id] = {
          name: i.id,
          total: 0,
        })
    )
    let buildings = this.map.queryRenderedFeatures(
      [this.startPoint, this.endPoint],
      {
        layers: ids,
      }
    )
    buildings.forEach((feature) => {
      statistics[feature.layer.id].total++
    })
    let html = `<div>总楼栋数：${buildings.length}</div>`
    for (let i in statistics) {
      html += `<div>${statistics[i].name}楼栋数：${statistics[i].total}</div>`
    }
    this.dom.innerHTML = html
  }
  bindEvent = () => {
    this.map.on('mousedown', this.onMouseDown)
    this.map.on('mouseup', this.onMouseUp)
  }
  destroy = () => {
    this.map.dragPan.enable()
    this.removeSource()
    this.map.off('mousedown', this.onMouseDown)
    this.map.off('mouseup', this.onMouseUp)
    this.dom.style.display = 'none'
  }
}

export class clickSpaceSearch {
  map = null
  layers = []
  sourceId = 'click-space-search-polygon'
  geojson = {
    type: 'geojson',
    data: {
      type: 'Feature',
      geometry: {
        type: 'Polygon',
        coordinates: [[]],
      },
    },
  }
  layer = {
    id: 'click-search-polygon-layer',
    source: this.sourceId,
    type: 'fill',
    paint: {
      'fill-color': 'blue',
      'fill-opacity': 0.2,
    },
  }
  lineLayer = {
    id: 'click-search-polygon-line-layer',
    source: this.sourceId,
    type: 'line',
    paint: {
      'line-color': 'blue',
      'line-width': 2,
      'line-opacity': 0.5,
    },
  }
  lngs = []
  points = []
  move = []
  canMove = false
  tipMarker = null
  closeMarker = null
  vm = null
  constructor(map, layers, vue) {
    this.map = map
    this.layers = layers
    this.vm = vue
  }
  init = () => {
    this.addSources()
    this.bindEvent()
  }
  addSources = () => {
    if (!this.map.getSource(this.sourceId)) {
      this.map.addSource(this.sourceId, this.geojson)
    }
    if (!this.map.getLayer(this.layer.id)) {
      this.map.addLayer(this.layer)
      this.map.addLayer(this.lineLayer)
    }
    this.lngs = []
    this.points = []
    this.move = []
    this.setLatlng()
  }
  setLatlng = () => {
    this.geojson.data.geometry.coordinates = [[...this.lngs, this.move]]
    this.map.getSource(this.sourceId).setData(this.geojson.data)
  }
  onClick = (e) => {
    let { lng, lat } = e.lngLat
    if (!this.canMove) {
      this.lngs = []
      this.points = []
      this.tipMarker = new D2c.Marker({
        element: this.createTipElement('双击结束绘制'),
        offset: [0, -25],
      })
        .setLngLat({ lng: 0, lat: 0 })
        .addTo(this.map)
      this.vm.showDrawBtn = true
    }
    this.lngs.push([lng, lat])
    this.move = [lng, lat]
    this.points.push(e.point)
    this.canMove = true
    this.setLatlng()
  }
  onMouseMove = (e) => {
    if (this.canMove) {
      let { lng, lat } = e.lngLat
      this.move = [lng, lat]
      this.setLatlng()
      this.tipMarker.setLngLat(e.lngLat)
    }
  }
  onDblclick = () => {
    this.lngs.pop()
    this.points.pop()
    this.move = this.lngs[0]
    this.canMove = false
    this.setLatlng()
    this.tipMarker.remove()
    this.tipMarker = null
    this.vm.showDrawBtn = false
    this.map.off('click', this.onClick)
    this.map.off('mousemove', this.onMouseMove)
    this.map.off('dblclick', this.onDblclick)
    // this.addCloseMarker()
  }
  addCloseMarker = () => {
    let div = document.createElement('div')
    div.innerHTML = 'X'
    div.style.backgroundColor = '#fff'
    div.style.padding = '5px'
    div.style.border = '1px solid #ccc'
    div.style.borderRadius = '50%'
    div.onclick = this.clearArea
    this.closeMarker = new D2c.Marker({
      element: div,
      offset: [0, -25],
    })
      .setLngLat(this.lngs[this.lngs.length - 1])
      .addTo(this.map)
  }
  clearArea = () => {
    this.clear()
    this.vm.showDrawBtn = true
    // this.closeMarker.remove()
    // this.closeMarker = null
    // setTimeout(() => {
    //   this.bindEvent();
    // }, 50);
  }
  createTipElement = (text) => {
    let div = document.createElement('div')
    div.innerText = text
    div.style.backgroundColor = '#fff'
    div.style.padding = '5px'
    div.style.border = '1px solid #ccc'
    div.style.borderRadius = '5px'
    return div
  }
  bindEvent = () => {
    this.map.on('click', this.onClick)
    this.map.on('mousemove', this.onMouseMove)
    this.map.on('dblclick', this.onDblclick)
  }
  clear = () => {
    this.lngs = []
    this.points = []
    this.move = []
    this.setLatlng()
  }
  destroy = () => {
    if (this.map.getLayer(this.layer.id)) {
      this.map.removeLayer(this.layer.id)
      this.map.removeLayer(this.lineLayer.id)
    }
    if (this.map.getSource(this.sourceId)) {
      this.map.removeSource(this.sourceId)
    }
    this.map.off('click', this.onClick)
    this.map.off('mousemove', this.onMouseMove)
    this.map.off('dblclick', this.onDblclick)
    if (this.tipMarker) {
      this.tipMarker.remove()
    }
    if (this.closeMarker) {
      this.closeMarker.remove()
    }
  }
}
